package com.zijidelu.luframework.application.domain.event;

import com.zijidelu.luframework.domain.event.DomainEvent;
import com.zijidelu.luframework.domain.event.DomainEventPublisher;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;

/**
 * Spring 领域事件发布器实现类。
 *
 * @author ZIJIDELU
 * @datetime 2025/10/14 23:27
 */
@Component
public class DefaultDomainEventPublisher implements DomainEventPublisher {
    private final ApplicationEventPublisher applicationEventPublisher;

    private final Executor executor;

    public DefaultDomainEventPublisher(
            ApplicationEventPublisher applicationEventPublisher,
            @Qualifier("domainEventExecutor") Executor executor) {
        this.applicationEventPublisher = applicationEventPublisher;
        this.executor = executor;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void publishEvent(DomainEvent<? extends Serializable> event) {
        if (Objects.isNull(event)) {
            throw new IllegalArgumentException("Domain event cannot be null");
        }

        applicationEventPublisher.publishEvent(event);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void publishEventList(List<DomainEvent<? extends Serializable>> events) {
        if (Objects.isNull(events)) {
            throw new IllegalArgumentException("Domain event list cannot be null");
        }

        if (events.isEmpty()) {
            return;
        }

        for (DomainEvent<? extends Serializable> event : events) {
            publishEvent(event);
        }
    }

    @Override
    public void publishEventAsync(DomainEvent<? extends Serializable> event) {
        executor.execute(() -> publishEvent(event));
    }

    @Override
    public void publishEventListAsync(List<DomainEvent<? extends Serializable>> events) {
        executor.execute(() -> publishEventList(events));
    }

}
